﻿using System;
using System.Collections.Generic;
using System.Linq;
using Internal.KuiHuaBaoDian.Services.Battle;
using Internal.KuiHuaBaoDian.Services.Battle.Data;
using KuiHuaBaoDian.Services.Battle.Entity;
using UnityEngine.Pool;

namespace KuiHuaBaoDian.Services.Battle.Data {

    /// <summary>
    /// 战斗融合数据
    /// </summary>
    public interface IReadOnlyBattleFusionData : IReadOnlyF64FusionData, IReadOnlyBattleData {

        /// <summary>
        /// 数据子项
        /// </summary>
        public interface IItem : IReadOnlyBattleData {

            /// <summary>
            /// 应用过滤器
            /// </summary>
            /// <param name="owner">来源数据列表</param>
            /// <param name="takedItems">已忽略数据集</param>
            bool ApplyFilter(IEnumerable<IItem> owner, IReadOnlyCollection<IItem> takedItems);
        }

        /// <summary>
        /// 数据子项过滤器
        /// </summary>
        public interface IItemFilter {

            /// <summary>
            /// 是否忽略
            /// </summary>
            /// <param name="owner">项拥有者</param>
            /// <param name="data">比对项</param>
            /// <param name="takedItems">已经忽略项</param>
            bool IsIgnore(IEnumerable<IItem> owner, IItem data, IReadOnlyCollection<IItem> takedItems);

            //[Implement(typeof(IDFR_BattleEffectFilter))]
            //internal sealed class DFR_BattleEffectFilter : IDFR_BattleEffectFilter {

            //    public bool IsIgnore(IEnumerable<IDFR_ReadOnlyBattleFusionData.IItem> owner, IDFR_ReadOnlyBattleFusionData.IItem data, IReadOnlyCollection<IDFR_ReadOnlyBattleFusionData.IItem> takedItems) {
            //        var model = BattleSkillServiceBase.Instance.GetEffectModel(data.EntityInstanceID);
            //        if (model == null) {
            //            return false;
            //        }
            //        var result = true;
            //        if (result && model.IsUnique) {
            //            result = CheckUnique(owner, data, takedItems);
            //        }
            //        return !result;
            //    }

            //    private bool CheckUnique(IEnumerable<IDFR_ReadOnlyBattleFusionData.IItem> owner, IDFR_ReadOnlyBattleFusionData.IItem data, IReadOnlyCollection<IDFR_ReadOnlyBattleFusionData.IItem> takedItems) {
            //        return !takedItems.Any(item => item.EntityInstanceID.ID == data.EntityInstanceID.ID);
            //    }
            //}
        }

        new IBattleFusionData AsReadWrite();

        /// <summary>
        /// 是否可深度过滤
        /// </summary>
        bool IsDeepFilter { get; }
    }

    /// <summary>
    /// 战斗融合数据
    /// </summary>
    public interface IValueChangedBattleFusionData : IReadOnlyBattleFusionData, IValueChangedF64FusionData, IValueChangedBattleData {
    }

    /// <summary>
    /// 战斗融合数据
    /// </summary>
    public interface IBattleFusionData : IValueChangedBattleFusionData, IF64FusionData {
    }

    [Implement(typeof(IReadOnlyBattleFusionData))]
    [Implement(typeof(IValueChangedBattleFusionData))]
    [Implement(typeof(IBattleFusionData))]
    internal sealed class KHBD_BattleFusionData : KHBD_FusionData<F64>, IBattleFusionData, IReadOnlyBattleFusionData.IItem, IBattleDataInternal, IBattleFusionDataInternal {

        IBattleData IReadOnlyBattleData.AsReadWrite() => throw new NotSupportedException($"{nameof(IReadOnlyBattleData)}.{nameof(IReadOnlyBattleData.AsReadWrite)} 已被 {nameof(IReadOnlyBattleFusionData)}.{nameof(IReadOnlyBattleFusionData.AsReadWrite)} 覆盖");
        IBattleFusionData IReadOnlyBattleFusionData.AsReadWrite() {
            AssertDispose();
            return this;
        }

        private BattleEntityInstanceID m_EntityInstanceID;
        public BattleEntityInstanceID EntityInstanceID {
            get {
                AssertDispose();
                return m_EntityInstanceID;
            }
        }

        private bool m_IsDeepFilter;
        public bool IsDeepFilter {
            get {
                AssertDispose();
                return m_IsDeepFilter;
            }
        }

        private bool m_IsRoot;
        public bool IsRoot {
            get {
                AssertDispose();
                return m_IsRoot;
            }
        }

        void IBattleFusionDataInternal.SetIsRoot(bool isRoot) {
            AssertDispose();
            m_IsRoot = isRoot;
        }

        private IReadOnlyList<IReadOnlyBattleFusionData.IItem> m_CachedItemList;

        protected override void Release() {
            DoClear();
            m_EntityInstanceID = BattleEntityInstanceID.Empty;
            m_IsDeepFilter = false;
            m_IsRoot = false;
            m_CachedValue = GetDefaultValue();
            base.Release();
        }

        public override F64 Value {
            get {
                AssertDispose();
                if (m_IsRoot) {
                    return GetValue();
                } else {
                    return base.Value;
                }
            }
        }

        private F64 m_CachedValue;

        private F64 GetValue() {
            if (IsDirty) {
                m_CachedItemList = GetItemEnumerable().ToArray();
                m_CachedValue = GetDefaultValue();
                var taskedItemSet = HashSetPool<IReadOnlyBattleFusionData.IItem>.Get();
                foreach (var item in m_CachedItemList) {
                    if (!item.ApplyFilter(m_CachedItemList, taskedItemSet)) {
                        taskedItemSet.Add(item);
                        m_CachedValue = Calculate(m_CachedValue, item.Value);
                    }
                }
                m_CachedValue = Clamp(m_CachedValue, MinValue, MaxValue);
                HashSetPool<IReadOnlyBattleFusionData.IItem>.Release(taskedItemSet);
                ValueCached();
            }
            return m_CachedValue;
        }

        private void DoClear() {
            m_CachedItemList = null;
        }

        public override void Clear() {
            AssertDispose();
            DoClear();
            base.Clear();
        }

        void IBattleDataInternal.EnableFilter(BattleEntityInstanceID entityInstanceID) {
            AssertDispose();
            m_EntityInstanceID = entityInstanceID;
        }

        void IBattleFusionDataInternal.EnableFilter(bool isDeepFilter) {
            AssertDispose();
            m_IsDeepFilter = isDeepFilter;
        }

        protected override F64 GetDefaultValue() => default;

        protected override F64 Calculate(F64 current, F64 next) {
            if (F64.MaxValue == current || F64.MaxValue == next) {
                return F64.MaxValue;
            } else if (F64.MinValue == current || F64.MinValue == next) {
                return F64.MinValue;
            } else {
                return current + next; // TODO: 需要处理数字越界
            }
        }

        protected override F64 GetDefaultMaxValue() => F64.MaxValue;

        protected override F64 GetDefaultMinValue() => F64.MinValue;

        protected override F64 Clamp(F64 value, F64 min, F64 max) => F64.Clamp(value, min, max);

        bool IReadOnlyBattleFusionData.IItem.ApplyFilter(IEnumerable<IReadOnlyBattleFusionData.IItem> owner, IReadOnlyCollection<IReadOnlyBattleFusionData.IItem> takedItems) {
            AssertDispose();
            return (BattleService.Instance as IBattleServiceInternal).ApplyFusionDataItemFilter(owner, this, takedItems);
        }

        private IEnumerable<IReadOnlyBattleFusionData.IItem> GetItemEnumerable() {
            if (Items == null) {
                yield break;
            }
            foreach (var source in Items) {
                if (source is IReadOnlyBattleFusionData.IItem item) {
                    if (source is KHBD_BattleFusionData fusionData && fusionData.IsDeepFilter) {
                        var enumerable = fusionData.IsDirty ? fusionData.GetItemEnumerable() : fusionData.m_CachedItemList;
                        if (enumerable != null) {
                            foreach (var fusionItem in enumerable) {
                                yield return fusionItem;
                            }
                        }
                    } else {
                        yield return item;
                    }
                }
            }
        }
    }
}

namespace Internal.KuiHuaBaoDian.Services.Battle.Data {

    public interface IBattleFusionDataInternal {

        void EnableFilter(bool isDeepFilter);

        void SetIsRoot(bool isRoot);
    }
}